#ifndef AER_POSTPROCESS_HPP_
#define AER_POSTPROCESS_HPP_

#include "../aerDefs.hpp"
#include <vector>

#include "aerPostEffect.hpp"


namespace aer {

///
/// Handles post-processing effects
///
class PostProcess
{
  private:
    typedef std::vector<PostEffect*> EffectArray;
    typedef EffectArray::iterator    EffectIterator;
  
  
  private:
    EffectArray m_effects;
    bool m_bInitialized;
    
  
  public:
    PostProcess() : m_bInitialized(false) {}
    //~PostProcess();
    
    
    void addEffect(PostEffect *pEffect) 
    { 
      m_effects.push_back(pEffect); 
    }

    /// Init effects
    void init()
    {
      AER_CHECK( "Warning : no post-effects provided." && !m_effects.empty() )
      
      EffectIterator it;
      for (it=m_effects.begin(); it!=m_effects.end(); ++it) {
        (*it)->init();
      }
      
      // Set last effect to be targeted to the screen
      // (alternatively, create a special effect for screen mapping)
      (*(it-1))->setTarget( PostEffect::SCREEN );//
      
      m_bInitialized = true;
    }
    
        
    void resize(const U32 width, const U32 height)
    {
      for (EffectIterator it=m_effects.begin(); it!=m_effects.end(); ++it) {
        (*it)->resize( width, height);
      }
    }
    
    /// Links external data to effects' input
    template<typename T>
    bool linkInput( const char *name, T *pInput)
    {
      bool bLinked = false;
      
      for (EffectIterator it=m_effects.begin(); it!=m_effects.end(); ++it) 
      {
        bool bStatus = (*it)->linkInput( name, pInput);
        bLinked = bStatus || bLinked;
      }
      
      return bLinked;
    }
        
    /// Link effects together to match input-output
    void link() 
    {
      AER_ASSERT( "Error : post-effects not initialized." && m_bInitialized );
      
      /// Link effects
      if (m_effects.size() < 2) {
        return;
      }
      
      for (EffectIterator it=m_effects.begin()+1; it!=m_effects.end(); ++it) {
        (*it)->linkEffect( *(it-1) );
      }
    }
    
    void run()
    {
      for (EffectIterator it=m_effects.begin(); it!=m_effects.end(); ++it) {
        (*it)->apply();
      }
    }
    
    void clear() 
    { 
      m_effects.clear(); 
    }

};
  
} // aer

#endif //AER_POSTPROCESS_HPP_
